######################################################################
# Descr: Вспомогательный файл для работы с СУБД
#
# В файле определяются переменные для работы с БД, все используемые
# в системе SQL-выражения и функция получения результата выборки.
#
# Примечание:
#
#   Файл должен встраиваться в скрипт после определения всех
#   общих и индивидуальных параметров узла.
#
# Sybase SQL Anywhere
# -------------------
#
# SQL-выражения, которые возвращают какие-либо значения должны
# заканчиваться соответствующим select'ом без разделителя
# операторов в конце. В данном случае используется особенность
# СУБД, позволяющее перенаправлять результат выборки в файл
# (см. функцию sql_valuelist).
# 
######################################################################

# ********************************************************************
# Общие переменные

SQL_UPPER=lower		# Имя функции sql, переводящей строку-аргумент
			# в строчные буквы (особенность postgreSQL)

SQL_SYSFIELD1=packet		# Служебные поля, добавляемые в каждую
SQL_SYSFIELD2=initpacket	# синхронизируемую таблицу:
				#   Packet     - номер пакета 
				#   InitPacket - номер пакета

SQL_FIELD_IN_PKEY=1	# Признак вхождения поля в первичный ключ
			# в метаданных СУБД

SQL_CURSORNAME="cur_<owner>_<table>"	# Имя курсора, используемое при
					# обновлении данных.
					# Sybase требует уникальности
					# данного идентификатора в
					# пределах скрипта.

SQL_FIELDPREFIX1=cur_			#
SQL_FIELDPREFIX2=$SQL_FIELDPREFIX1	#
SQL_FIELDPREFIX_OLD=OLD                 # Префикс полей для триггера
SQL_FIELDPREFIX_NEW=NEW	                # Префикс полей для триггера

# Для Oracle:
#   SQL_CURSORNAME=cur
#   SQL_FIELDPREFIX1=
#   SQL_FIELDPREFIX2=$SQL_CURSORNAME.

SQL_PREFIX_DELTABLE=del		# Префикс в названии таблиц, содержащих
				# удаленные записи соответствующих
				# таблиц
SQL_PREFIX_TEMPTABLE=temp	# Префикс в названии временных таблиц
				# для загрузки данных (update)
SQL_PREFIX_UNLOADTABLE=unload	# Префикс в названии временных таблиц
				# для выгрузки данных (prepare)

SQL_COUNT_FILE=$PATH_TEMP/new_packet	# файл, куда помещается номер
					# сформированного пакета

# ********************************************************************
# Таблица соответствий между кодами типов полей в метаданных и
# написанием типов в операторе create table стандарта SQL 92.
#
# Формат: type_<код типа>='<название типа>'[([,]]
#
#         Если указана открывающаяся скобка,
#         то в определении поля данного типа
#         должен указываться ее размер.
#         Если плюс к этой скобке указана
#         запятая, то размер должен состоять
#         из двух частей.

type_char='character('
type_character='character('
type_character_varying='varchar('
type_varchar='varchar('
type_smallint='smallint'
type_integer='integer'
type_numeric='numeric(,'
type_float='real'
type_double_precision='real'
type_real='real'
type_date='date'
type_time='time'
type_timestamp='timestamp'
type_timestamp_without_time_zone='timestamp'
type_bigint='bigint'
type_uuid='varchar('
type_user_defined='varchar('

# ********************************************************************
# Шаблоны SQL-выражений

# SQL-скрипт обновления существующих системных таблиц.
# Должен выполняться ДО выполнения SQL-скрипта обновления
# системы.

SQL_SYSTEM_UPGRADE=\
"
"

# SQL-скрипт создания служебных таблиц

SQL_SYSTEM_TABLE1=\
"
CREATE TABLE <schema>.syncMAIN
(
  version_major smallint not null,
  version_minor smallint not null,
  current_packet int default 0 not null
);
"

SQL_SYSTEM_TABLE2=\
"
CREATE TABLE <schema>.syncNODES
(
  name varchar(30) not null unique,
  prepared int default 0 not null,
  updated int default 0 not null
);
"

SQL_SYSTEM_TABLE3=\
"
CREATE TABLE <schema>.syncSTREAM
(
  sender varchar(30) not null,
  receiver varchar(30) not null,
  stage int not null,
  num_packet int not null,
  time_packet timestamp default current_timestamp not null,

  primary key (sender, receiver, stage, num_packet)
);
"

SQL_SYSTEM_TABLE4=\
"
CREATE TABLE <schema>.syncPROCESSING
(
  sender varchar(30) not null,
  receiver varchar(30) not null,
  num_packet int not null,
  dt_receive timestamp,
  dt_process timestamp,
  st_process int default 0,

  primary key (sender, receiver, num_packet)
);
"

# SQL-скрипт создания служебных триггеров
# Параметры шаблона:
#   this - имя данного узла

SQL_SYSTEM_TRIGGERS=\
"
CREATE OR REPLACE FUNCTION <schema>.ftemp()
 RETURNS integer AS
\$BODY\$
BEGIN
   if exists(SELECT * FROM information_schema.triggers
              WHERE trigger_name = 'zzz_syncnodes_stream_au'
	        AND trigger_schema = '<schema>') then
      DROP TRIGGER zzz_syncNODES_Stream_AU ON <schema>.syncNODES;
   end if;
   return 1;
END;
\$BODY\$
LANGUAGE 'plpgsql'; 

SELECT <schema>.ftemp();

DROP FUNCTION <schema>.ftemp();

CREATE OR REPLACE FUNCTION <schema>.zzz_syncNODES_Stream_Func_AU()
  RETURNS trigger AS
\$BODY\$
BEGIN
if $SQL_FIELDPREFIX_OLD.prepared < $SQL_FIELDPREFIX_NEW.prepared
  then
    INSERT INTO <schema>.syncSTREAM(sender, receiver, stage, num_packet, time_packet)
      VALUES('<this>',$SQL_FIELDPREFIX_NEW.name, 0, $SQL_FIELDPREFIX_NEW.prepared, now());
  end if;

  if $SQL_FIELDPREFIX_OLD.updated < $SQL_FIELDPREFIX_NEW.updated
  then
    INSERT INTO <schema>.syncSTREAM(sender, receiver, stage, num_packet, time_packet)
      VALUES($SQL_FIELDPREFIX_NEW.name, '<this>', 0, $SQL_FIELDPREFIX_NEW.updated, now());
  end if;
  RETURN NULL;
END;
\$BODY\$
LANGUAGE 'plpgsql';  

CREATE TRIGGER zzz_syncNODES_Stream_AU
  AFTER UPDATE on <schema>.syncNODES
  FOR EACH ROW
  EXECUTE PROCEDURE <schema>.zzz_syncNODES_Stream_Func_AU();

"

# SQL-скрипт установки в БД языка plpgsql.
# Параметры шаблона:
#
# SELECT * FROM pg_catalog.pg_language WHERE lanname = 'plpgsql'

SQL_CREATE_PLPGSQL=\
"  CREATE LANGUAGE 'plpgsql';
"

# SQL-скрипт установки в БД служебной схемы
# Параметры шаблона:
#   schema           - имя схемы
# SELECT * FROM pg_catalog.pg_namespace WHERE nspname='<schema>'

SQL_CREATE_SCHEMA=\
"  CREATE SCHEMA <schema>;
"

# SQL-скрипт установки в БД всего необходимого для системы.
# Параметры шаблона:
#   this           - имя данного узла
#   data_ver_major - версия метаданных
#   data_ver_minor - версия метаданных

SQL_SYSTEM_INSTALL=\
"
CREATE OR REPLACE FUNCTION <schema>.ftemp()
 RETURNS integer AS
\$BODY\$
BEGIN
   if exists(SELECT * FROM information_schema.tables
              WHERE table_name = 'syncmain'
	        AND table_schema = '<schema>') then
      DROP TABLE <schema>.syncMAIN;
   end if;
   
   $SQL_SYSTEM_TABLE1
   
   if exists(SELECT * FROM information_schema.tables
              WHERE table_name = 'syncnodes'
	        AND table_schema = '<schema>') then
      DROP TABLE <schema>.syncNODES;
   end if;

   $SQL_SYSTEM_TABLE2
   
   if exists(SELECT * FROM information_schema.tables
              WHERE table_name = 'syncstream'
	        AND table_schema = '<schema>') then
      DROP TABLE <schema>.syncSTREAM;
   end if;
   
   $SQL_SYSTEM_TABLE3

   if exists(SELECT * FROM information_schema.tables
              WHERE table_name = 'syncprocessing'
	        AND table_schema = '<schema>') then
      DROP TABLE <schema>.syncPROCESSING;
   end if;
   
   $SQL_SYSTEM_TABLE4
   
   return 1;
END;
\$BODY\$
LANGUAGE 'plpgsql';

SELECT <schema>.ftemp();

DROP FUNCTION <schema>.ftemp();

$SQL_SYSTEM_TRIGGERS

INSERT INTO <schema>.syncMAIN(version_major, version_minor)
                       VALUES(<data_ver_major>, <data_ver_minor>);

"

# SQL-скрипт обновления системы в БД.
# Если необходимо выполнить SQL-скрипт обновления существующих
# системных таблиц, то он должен выполняться ДО выполнения
# данного скрипта.
# Параметры шаблона:
#   this           - имя данного узла
#   data_ver_major - версия метаданных
#   data_ver_minor - версия метаданных

SQL_SYSTEM_UPDATE=\
"
CREATE OR REPLACE FUNCTION <schema>.ftemp()
 RETURNS integer AS
\$BODY\$
BEGIN
   if not exists(SELECT * FROM information_schema.tables
              WHERE table_name = 'syncmain'
	        AND table_schema = '<schema>') then
      $SQL_SYSTEM_TABLE1
      INSERT INTO <schema>.syncMAIN(version_major, version_minor)
                         values(<data_ver_major>, <data_ver_minor>);
   end if;
   
   if not exists(SELECT * FROM information_schema.tables
              WHERE table_name = 'syncnodes'
	        AND table_schema = '<schema>') then
      $SQL_SYSTEM_TABLE2
   end if;
  
   if not exists(SELECT * FROM information_schema.tables
              WHERE table_name = 'syncstream'
	        AND table_schema = '<schema>') then
      $SQL_SYSTEM_TABLE3
   end if;

   if not exists(SELECT * FROM information_schema.tables
              WHERE table_name = 'syncprocessing'
	        AND table_schema = '<schema>') then
      $SQL_SYSTEM_TABLE4
   end if;
   
   return 1;
END;
\$BODY\$
LANGUAGE 'plpgsql';

SELECT <schema>.ftemp();

DROP FUNCTION <schema>.ftemp();

$SQL_SYSTEM_TRIGGERS

UPDATE <schema>.syncMAIN SET version_major = <data_ver_major>, 
                             version_minor = <data_ver_minor>;
    
"

# SQL-скрипт удаления из БД всего, что относится к системе

SQL_SYSTEM_UNINSTALL=\
"
CREATE OR REPLACE FUNCTION <schema>.ftemp()
 RETURNS integer AS
\$BODY\$
BEGIN
   if exists(SELECT * FROM information_schema.tables
              WHERE table_name = 'syncmain'
	        AND table_schema = '<schema>') then
      DROP TABLE <schema>.syncMAIN;
   end if;
   if exists(SELECT * FROM information_schema.tables
              WHERE table_name = 'syncnodes'
	        AND table_schema = '<schema>') then
      DROP TABLE <schema>.syncNODES;
   end if;
   if exists(SELECT * FROM information_schema.tables
              WHERE table_name = 'syncstream'
	        AND table_schema = '<schema>') then
      DROP TABLE <schema>.syncSTREAM;
   end if;
   if exists(SELECT * FROM information_schema.tables
              WHERE table_name = 'syncprocessing'
	        AND table_schema = '<schema>') then
      DROP TABLE <schema>.syncPROCESSING;
   end if;
   if exists(SELECT * FROM information_schema.routines
              WHERE routine_name = 'zzz_syncnodes_stream_func_au'
	        AND routine_schema = '<schema>'
		AND data_type LIKE '%trigger%') then
      DROP FUNCTION <schema>.zzz_syncnodes_stream_func_au();
   end if;
 
   return 1;
END;
\$BODY\$
LANGUAGE 'plpgsql';

SELECT <schema>.ftemp();

DROP FUNCTION <schema>.ftemp();
"

# Вернуть признак установлена ли система в базе данных.
# Любое значение - система установлена,
# ничего - система не установлена.

SQL_SYSTEM_STATUS=\
"
SELECT 'ok'
  FROM information_schema.tables
 WHERE table_name = 'syncmain'
   AND table_schema = '<schema>'
"

# Вернуть версию метаданных системы в БД

SQL_SYSTEM_STATUS_VERSION=\
"
SELECT version_major || '.' || version_minor FROM <schema>.syncMAIN
"

# Вернуть текущий номер пакета

SQL_SYSTEM_STATUS_COVER=\
"
SELECT current_packet FROM <schema>.syncMAIN
"

# Вернуть список удаленных узлов, зарегистрированных в системе

SQL_SYSTEM_STATUS_NODES=\
"
SELECT name || ':[' || prepared || ',' || updated || ']'
  FROM <schema>.syncNODES
 ORDER BY name
"

# SQL-скрипт добавления в систему удаленного узла

SQL_NODE_ADD=\
"
INSERT INTO <schema>.syncNODES(name) VALUES('<node>');
"

# SQL-скрипт создания таблицы узлов, если его нет

SQL_NODE_CREATE=\
"
CREATE OR REPLACE FUNCTION <schema>.ftemp()
 RETURNS integer AS
\$BODY\$
BEGIN
   if not exists(SELECT * FROM information_schema.tables
                  WHERE table_name = 'syncnodes'
	            AND table_schema = '<schema>') then
     $SQL_SYSTEM_TABLE2  
   end if;
   
   return 1;
END;
\$BODY\$
LANGUAGE 'plpgsql';

SELECT <schema>.ftemp();

DROP FUNCTION <schema>.ftemp();

"

# SQL-скрипт удаления из системы удаленного узла

SQL_NODE_REMOVE=\
"
CREATE OR REPLACE FUNCTION <schema>.ftemp()
 RETURNS integer AS
\$BODY\$
BEGIN
   if exists(SELECT * FROM information_schema.tables
              WHERE table_name = 'syncnodes'
	        AND table_schema = '<schema>') then
      DELETE FROM <schema>.syncnodes WHERE name = '<node>';
   end if;
   
   return 1;
END;
\$BODY\$
LANGUAGE 'plpgsql';

SELECT <schema>.ftemp();

DROP FUNCTION <schema>.ftemp();

"

# Вернуть список удаленных узлов, зарегистрированных в системе

SQL_NODELIST=\
"
SELECT name
  FROM <schema>.syncNODES
 ORDER BY name
"

# SQL-скрипт создания таблицы для удаленных записей
# Параметры шаблона:
#   owner          - владелец таблицы
#   table          - имя таблицы
#   all_fields_def - определения всех полей таблицы (кроме служебных полей)
#                    из удаленной БД, перечисленные через запятую

SQL_WATCHDELETE_TABLE=\
"
CREATE TABLE <owner>.<table>_$SQL_PREFIX_DELTABLE
(
  <all_fields_def>,
  $SQL_SYSFIELD1 integer DEFAULT 0 NOT NULL,
  $SQL_SYSFIELD2 integer DEFAULT 0 NOT NULL
);
"

# SQL-скрипт создания триггера на удаление записи
# Параметры шаблона:
#   owner          - владелец таблицы
#   table          - имя таблицы
#   all_fields     - список всех полей таблицы (кроме служебных полей),
#                    перечисленных через запятую
#   all_values     - список всех полей таблицы (кроме служебных полей)
#                    в виде:
#                      old_values.<field1>,
#                      old_values.<field2>,
#                      ...
#                      old_values.<fieldN>

SQL_WATCHDELETE_TRIGGER=\
"
CREATE OR REPLACE FUNCTION <schema>.ftemp()
 RETURNS integer AS
\$BODY\$
BEGIN
   if exists(SELECT * FROM information_schema.triggers
              WHERE trigger_name = 'zzz_<table>_sync_ad'
	        AND trigger_schema = '<owner>') then
      DROP TRIGGER zzz_<table>_sync_ad ON <owner>.<table>;
   end if;
      
   return 1;
END;
\$BODY\$
LANGUAGE 'plpgsql'; 

SELECT <schema>.ftemp();

DROP FUNCTION <schema>.ftemp();

CREATE OR REPLACE FUNCTION <owner>.zzz_<table>_sync_func_ad()
  RETURNS trigger AS
\$BODY\$
BEGIN
  if ($SQL_FIELDPREFIX_OLD.$SQL_SYSFIELD2 <> 0) then
     INSERT INTO <owner>.<table>_$SQL_PREFIX_DELTABLE(
               <all_fields>,
               $SQL_SYSFIELD1,
               $SQL_SYSFIELD2)
        VALUES(
               <all_values>,
               0,
               $SQL_FIELDPREFIX_OLD.$SQL_SYSFIELD2
              ); 
  end if;
  RETURN NULL;
END;
\$BODY\$
LANGUAGE 'plpgsql';

CREATE TRIGGER zzz_<table>_sync_ad
  AFTER DELETE on <owner>.<table>
  FOR EACH ROW
  EXECUTE PROCEDURE <owner>.zzz_<table>_sync_func_ad();

"

# Общая часть SQL-скриптов для добавления/обновления таблицы для
# ее синхронизации.
# Параметры шаблона:
#   owner          - владелец таблицы
#   table          - имя таблицы
#   all_fields_def - определения всех полей таблицы (кроме служебных полей)
#                    из удаленной БД, перечисленные через запятую
#   change_fields  - список всех полей таблицы (кроме служебных полей)
#                    в виде:
#                      old_values.<field1> <> new_values.<field1> or
#                      old_values.<field2> <> new_values.<field2> or
#                      ...
#                      old_values.<fieldN> <> new_values.<fieldN> or

SQL_TABLE_COMMON=\
"
CREATE OR REPLACE FUNCTION <schema>.ftemp()
 RETURNS integer AS
\$BODY\$
BEGIN

   if not exists(SELECT * FROM information_schema.columns
                  WHERE table_name = '<table>'
	            AND table_schema = '<owner>'
	            AND column_name = '$SQL_SYSFIELD1') then
      ALTER TABLE <owner>.<table> ADD $SQL_SYSFIELD1 integer DEFAULT 0 NOT NULL;
   end if;
   if not exists(SELECT * FROM information_schema.columns
                  WHERE table_name = '<table>'
                    AND table_schema = '<owner>'
	            AND column_name = '$SQL_SYSFIELD2') then
      ALTER TABLE <owner>.<table> ADD $SQL_SYSFIELD2 integer DEFAULT 0 NOT NULL;
   end if;
   
   if not exists(SELECT * FROM pg_indexes
                  WHERE indexname = 'i_<owner>_<table>_$SQL_SYSFIELD1') then
      CREATE INDEX i_<owner>_<table>_$SQL_SYSFIELD1 ON <owner>.<table>($SQL_SYSFIELD1);
   end if;

   if exists(SELECT * FROM information_schema.triggers
              WHERE trigger_name = 'zz_<table>_sync_bu1'
	        AND trigger_schema = '<owner>') then
      DROP TRIGGER zz_<table>_sync_bu1 ON <owner>.<table>;
   end if;
   
   if exists(SELECT * FROM information_schema.triggers
              WHERE trigger_name = 'zzz_<table>_sync_bu2'
	        AND trigger_schema = '<owner>') then
      DROP TRIGGER zzz_<table>_sync_bu2 ON <owner>.<table>;
   end if;
 
   if exists(SELECT * FROM information_schema.tables
              WHERE table_name = '<table>_$SQL_PREFIX_DELTABLE'
	        AND table_schema = '<owner>') then
      DROP TABLE <owner>.<table>_$SQL_PREFIX_DELTABLE;
   end if;
   
   return 1;
END;
\$BODY\$
LANGUAGE 'plpgsql'; 

SELECT <schema>.ftemp();

DROP FUNCTION <schema>.ftemp();

CREATE OR REPLACE FUNCTION <owner>.zz_<table>_sync_func_bu1()
  RETURNS trigger AS
\$BODY\$
BEGIN
  if ($SQL_FIELDPREFIX_NEW.$SQL_SYSFIELD1 <> $SQL_FIELDPREFIX_OLD.$SQL_SYSFIELD1
     and $SQL_FIELDPREFIX_NEW.$SQL_SYSFIELD1 <> -1
     and $SQL_FIELDPREFIX_OLD.$SQL_SYSFIELD2 = 0) 
     then
        $SQL_FIELDPREFIX_NEW.$SQL_SYSFIELD2 := $SQL_FIELDPREFIX_NEW.$SQL_SYSFIELD1;
  end if;
  RETURN NEW;
END;
\$BODY\$
LANGUAGE 'plpgsql';  

CREATE TRIGGER zz_<table>_sync_bu1
  BEFORE UPDATE on <owner>.<table>
  FOR EACH ROW
  EXECUTE PROCEDURE <owner>.zz_<table>_sync_func_bu1();

CREATE OR REPLACE FUNCTION <owner>.zzz_<table>_sync_func_bu2()
  RETURNS trigger AS
\$BODY\$
BEGIN
  if ($SQL_FIELDPREFIX_NEW.$SQL_SYSFIELD1 = $SQL_FIELDPREFIX_OLD.$SQL_SYSFIELD1
     and $SQL_FIELDPREFIX_NEW.$SQL_SYSFIELD2 = $SQL_FIELDPREFIX_OLD.$SQL_SYSFIELD2)
     then
        $SQL_FIELDPREFIX_NEW.$SQL_SYSFIELD1 := 0;
  end if;
  RETURN NEW;
END;
\$BODY\$
LANGUAGE 'plpgsql';

CREATE TRIGGER zzz_<table>_sync_bu2
  BEFORE UPDATE on <owner>.<table>
  FOR EACH ROW
  EXECUTE PROCEDURE <owner>.zzz_<table>_sync_func_bu2();

$SQL_WATCHDELETE_TABLE
"

# SQL-скрипт инициализации какой-либо таблицы для последующей
# ее синхронизации.
# Параметры шаблона:
#   owner          - владелец таблицы
#   table          - имя таблицы
#   all_fields_def - определения всех полей таблицы (кроме служебных полей)
#                    из удаленной БД, перечисленные через запятую
#   all_fields     - список всех полей таблицы (кроме служебных полей),
#                    перечисленных через запятую
#   all_values     - список всех полей таблицы (кроме служебных полей)
#                    в виде:
#                      old_values.<field1>,
#                      old_values.<field2>,
#                      ...
#                      old_values.<fieldN>
#   change_fields  - список всех полей таблицы (кроме служебных полей)
#                    в виде:
#                      old_values.<field1> <> new_values.<field1> or
#                      old_values.<field2> <> new_values.<field2> or
#                      ...
#                      old_values.<fieldN> <> new_values.<fieldN> or

SQL_TABLE_ADD=\
"
$SQL_TABLE_COMMON

$SQL_WATCHDELETE_TRIGGER

"

# SQL-скрипт обновления метаданных синхронизируемой таблицы
# Параметры шаблона:
#   owner          - владелец таблицы
#   table          - имя таблицы
#   all_fields_def - определения всех полей таблицы (кроме служебных полей)
#                    из удаленной БД, перечисленные через запятую
#   all_fields     - список всех полей таблицы (кроме служебных полей),
#                    перечисленных через запятую
#   all_values     - список всех полей таблицы (кроме служебных полей)
#                    в виде:
#                      old_values.<field1>,
#                      old_values.<field2>,
#                      ...
#                      old_values.<fieldN>
#   change_fields  - список всех полей таблицы (кроме служебных полей)
#                    в виде:
#                      old_values.<field1> <> new_values.<field1> or
#                      old_values.<field2> <> new_values.<field2> or
#                      ...
#                      old_values.<fieldN> <> new_values.<fieldN> or

SQL_TABLE_UPDATE=\
"
$SQL_TABLE_COMMON

$SQL_WATCHDELETE_TRIGGER

"

# SQL-скрипт выключения таблицы из процесса синхронизации
 
SQL_TABLE_REMOVE=\
"
CREATE OR REPLACE FUNCTION <schema>.ftemp()
 RETURNS integer AS
\$BODY\$
BEGIN
   if exists(SELECT * FROM information_schema.triggers
              WHERE trigger_name = 'zzz_<table>_sync_ad'
	        AND trigger_schema = '<owner>') then
      DROP TRIGGER zzz_<table>_sync_ad ON <owner>.<table>;
   end if;
   if exists(SELECT * FROM information_schema.routines
              WHERE routine_name = 'zzz_<table>_sync_func_ad'
	        AND routine_schema = '<owner>'
		AND data_type LIKE '%trigger%') then
      DROP FUNCTION <owner>.zzz_<table>_sync_func_ad();
   end if;
   
   if exists(SELECT * FROM information_schema.triggers
              WHERE trigger_name = 'zz_<table>_sync_bu1'
	        AND trigger_schema = '<owner>') then
      DROP TRIGGER zz_<table>_sync_bu1 ON <owner>.<table>;
   end if;
   if exists(SELECT * FROM information_schema.routines
              WHERE routine_name = 'zz_<table>_sync_func_bu1'
	        AND routine_schema = '<owner>'
		AND data_type LIKE '%trigger%') then
      DROP FUNCTION <owner>.zz_<table>_sync_func_bu1();
   end if;
   
   if exists(SELECT * FROM information_schema.triggers
              WHERE trigger_name = 'zzz_<table>_sync_bu2'
	        AND trigger_schema = '<owner>') then
      DROP TRIGGER zzz_<table>_sync_bu2 ON <owner>.<table>;
   end if;
   if exists(SELECT * FROM information_schema.routines
              WHERE routine_name = 'zzz_<table>_sync_func_bu2'
	        AND routine_schema = '<owner>'
		AND data_type LIKE '%trigger%') then
      DROP FUNCTION <owner>.zzz_<table>_sync_func_bu2();
   end if;
   
   if exists(SELECT * FROM pg_indexes
              WHERE indexname = 'i_<owner>_<table>_$SQL_SYSFIELD1') then
      DROP INDEX <owner>.i_<owner>_<table>_$SQL_SYSFIELD1;
   end if;

   if exists(SELECT * FROM information_schema.columns
              WHERE table_name = '<table>'
	        AND table_schema = '<owner>'
		AND column_name = '$SQL_SYSFIELD1') then
      ALTER TABLE <owner>.<table> DROP $SQL_SYSFIELD1;
   end if;
   if exists(SELECT * FROM information_schema.columns
              WHERE table_name = '<table>'
	        AND table_schema = '<owner>'
		AND column_name = '$SQL_SYSFIELD2') then
      ALTER TABLE <owner>.<table> DROP $SQL_SYSFIELD2;
   end if;
   
   if exists(SELECT * FROM information_schema.tables
              WHERE table_name = '<table>_$SQL_PREFIX_DELTABLE'
	        AND table_schema = '<owner>') then
      DROP TABLE <owner>.<table>_$SQL_PREFIX_DELTABLE;
   end if;
   if exists(SELECT * FROM information_schema.tables
              WHERE table_name = '<table>_$SQL_PREFIX_UNLOADTABLE'
	        AND table_schema = '<owner>') then
      DROP TABLE <owner>.<table>_$SQL_PREFIX_UNLOADTABLE;
   end if;
   
   return 1;
END;
\$BODY\$
LANGUAGE 'plpgsql'; 

SELECT <schema>.ftemp();

DROP FUNCTION <schema>.ftemp();

"

# SQL-скрипт включения слежения за удалением записей.
# Параметры шаблона:
#   owner          - владелец таблицы
#   table          - имя таблицы
#   all_fields_def - определения всех полей таблицы (кроме служебных полей)
#                    из удаленной БД, перечисленные через запятую
#   all_fields     - список всех полей таблицы (кроме служебных полей),
#                    перечисленных через запятую
#   all_values     - список всех полей таблицы (кроме служебных полей)
#                    в виде:
#                      old_values.<field1>,
#                      old_values.<field2>,
#                      ...
#                      old_values.<fieldN>

SQL_WATCHDELETE_ADD=\
"
CREATE OR REPLACE FUNCTION <schema>.ftemp()
 RETURNS integer AS
\$BODY\$
BEGIN
   if not exists(SELECT * FROM information_schema.tables
                  WHERE table_name = '<table>_$SQL_PREFIX_DELTABLE'
	            AND table_schema = '<owner>') then
      $SQL_WATCHDELETE_TABLE
   end if;
   
   return 1;
END;
\$BODY\$
LANGUAGE 'plpgsql'; 

SELECT <schema>.ftemp();

DROP FUNCTION <schema>.ftemp();

$SQL_WATCHDELETE_TRIGGER
"

# SQL-скрипт выключения слежения за удалением записей.
# Параметры шаблона:
#   owner          - владелец таблицы
#   table          - имя таблицы

SQL_WATCHDELETE_REMOVE=\
"
CREATE OR REPLACE FUNCTION <schema>.ftemp()
 RETURNS integer AS
\$BODY\$
BEGIN
   if exists(SELECT * FROM information_schema.triggers
              WHERE trigger_name = 'zzz_<table>_sync_ad'
	        AND trigger_schema = '<owner>') then
      DROP TRIGGER zzz_<table>_sync_ad ON <owner>.<table>;
   end if;
   if exists(SELECT * FROM information_schema.routines
              WHERE routine_name = 'zzz_<table>_sync_func_ad'
	        AND routine_schema = '<owner>'
		AND data_type LIKE '%trigger%') then
      DROP FUNCTION <owner>.zzz_<table>_sync_func_ad();
   end if;
   
   return 1;
END;
\$BODY\$
LANGUAGE 'plpgsql'; 

SELECT <schema>.ftemp();

DROP FUNCTION <schema>.ftemp();
"

# SQL-скрипт удаления таблицы
 
SQL_REMOVE_TABLE=\
"
DROP TABLE <owner>.<table>;
"

# Вернуть список временных таблиц в формате
# <владелец>.<имя таблицы>

SQL_TEMPTABLELIST=\
"
SELECT table_schema || '.' || table_name
  FROM information_schema.tables
 WHERE table_name LIKE '%_${SQL_PREFIX_TEMPTABLE}'
    OR table_name LIKE '%_${SQL_PREFIX_UNLOADTABLE}'
"

# Вернуть список синхронизируемых таблиц в формате
# <владелец>.<имя таблицы>

SQL_TABLELIST=\
"
SELECT DISTINCT table_schema || '.' || table_name
  FROM information_schema.columns
 WHERE column_name = '$SQL_SYSFIELD1'
   AND table_name NOT LIKE '%_$SQL_PREFIX_DELTABLE'
   AND table_name NOT LIKE '%_$SQL_PREFIX_TEMPTABLE'
   AND table_name NOT LIKE '%_$SQL_PREFIX_UNLOADTABLE'
"

# Установить номер последнего успешно сформированного пакета
# для определенного удаленного узла

SQL_PACKET_PREPARED_SET=\
"
UPDATE <schema>.syncNODES
   SET prepared = <number>
 WHERE name = '<node>';
"

# Вернуть номер последнего успешно сформированного пакета
# для определенного удаленного узла

SQL_PACKET_PREPARED_GET=\
"
SELECT prepared
  FROM <schema>.syncNODES
 WHERE name = '<node>'
"

# Установить номер последнего успешно обработанного пакета
# для определенного удаленного узла

SQL_PACKET_UPDATED_SET=\
"
  UPDATE <schema>.syncNODES
     SET updated = <number>
   WHERE name = '<node>';
"

# Вернуть номер последнего успешно обработанного пакета
# для определенного удаленного узла

SQL_PACKET_UPDATED_GET=\
"
SELECT updated
  FROM <schema>.syncNODES
 WHERE name = '<node>'
"

# Добавить данные о полученном пакете

SQL_PACKET_INSERT=\
"
INSERT INTO <schema>.syncPROCESSING(sender, receiver, num_packet, dt_receive)
       VALUES ('<sender>','<receiver>',<num_packet>,'<dt_receive>');
"

# Изменить статус обработки полученного пакета

SQL_PACKET_UPDATE_STATUS=\
"
UPDATE <schema>.syncPROCESSING 
   SET st_process=<status>, dt_process=now() 
 WHERE sender='<sender>'
   AND receiver='<receiver>'
   AND num_packet=<num_packet>;
"

# SQL-скрипт для формирования пакета - НАЧАЛО

SQL_DATA_PREPARE_BEFORE=\
"
    CREATE TEMP TABLE syncCOUNT
    (
      value int
    );
"

# SQL-скрипт для формирования пакета - ДЛЯ ОТДЕЛЬНОЙ ТАБЛИЦЫ
# Параметры шаблона:
#   owner         - владелец таблицы
#   table         - имя таблицы
#   node          - имя удаленного узла для которого готовится пакет
#   fields_def    - определения всех полей таблицы (кроме служебных полей),
#                   перечисленные через запятую
#   select_fields - названия всех полей (кроме служебных) в виде списка:
#                     $<field1> as $SQL_FIELDPREFIX1<field1>,
#                     $<field2> as $SQL_FIELDPREFIX1<field2>,
#                     ...
#                     $<fieldN> as $SQL_FIELDPREFIX1<fieldN>,
#                   Виртуальные поля в форме:
#                     <значение> as $SQL_FIELDPREFIX1<поле>
#   insert_fields - названия полей из select_fields в виде:
#                     $SQL_FIELDPREFIX2<field1>,
#                     $SQL_FIELDPREFIX2<field2>,
#                     ...
#                     $SQL_FIELDPREFIX2<fieldN>
#   insert_values - названия полей из insert_fields в виде:
#                     $SQL_FIELDPREFIX2<field1>,
#                     $SQL_FIELDPREFIX2<field2>,
#                     ...
#                     $SQL_FIELDPREFIX2<fieldN>
#   filter        - необязательное дополнительное условие на выборку
#                   данных из таблицы, присоединенное через and и
#                   обрамленное в круглые скобки
#   file_data     - полный путь и имя файла, куда будут складываться
#                   данные, выбранные из таблицы
#   file_del      - полный путь и имя файла, куда будут складываться
#                   значения первичного ключа записей, удаленных из
#                   таблицы со времени предыдущего формирования пакета

SQL_DATA_PREPARE_TABLE=\
"
  ----------- Prepare data for table <table>

  CREATE TEMP TABLE <table>_${SQL_PREFIX_UNLOADTABLE}
  (
   <fields_def>
  );

  INSERT INTO <table>_${SQL_PREFIX_UNLOADTABLE}(<insert_fields>)
       SELECT <select_fields>
         FROM <owner>.<table>
        WHERE ($SQL_SYSFIELD1 = 0 
           OR  $SQL_SYSFIELD1 > (SELECT prepared FROM <schema>.syncNODES
                                  WHERE name = '<node>')
              )
       <filter> ;

  UPDATE <owner>.<table>
     SET $SQL_SYSFIELD1 = (SELECT current_packet+1 FROM <schema>.syncMAIN)
   WHERE $SQL_SYSFIELD1 = 0;

  INSERT INTO syncCOUNT SELECT count(*) FROM <table>_${SQL_PREFIX_UNLOADTABLE};

  COPY <table>_${SQL_PREFIX_UNLOADTABLE} TO '<file_data>' CSV;

  TRUNCATE <table>_${SQL_PREFIX_UNLOADTABLE};

  INSERT INTO <table>_${SQL_PREFIX_UNLOADTABLE}(<insert_fields>)
       SELECT <select_fields>
         FROM <owner>.<table>_$SQL_PREFIX_DELTABLE
        WHERE ($SQL_SYSFIELD1 = 0 
           OR  $SQL_SYSFIELD1 > (SELECT prepared FROM <schema>.syncNODES
                                  WHERE name = '<node>')
              )
      AND $SQL_SYSFIELD2 <= (SELECT prepared FROM <schema>.syncNODES
                                  WHERE name = '<node>') 
      <filter> ;
  UPDATE <owner>.<table>_$SQL_PREFIX_DELTABLE
     SET $SQL_SYSFIELD1 = (SELECT current_packet+1 FROM <schema>.syncMAIN)
   WHERE $SQL_SYSFIELD1 = 0;

  INSERT INTO syncCOUNT SELECT count(*) FROM <table>_${SQL_PREFIX_UNLOADTABLE};

  COPY <table>_${SQL_PREFIX_UNLOADTABLE} TO '<file_del>' CSV;
"

# SQL-скрипт для формирования пакета - ДЛЯ ОТДЕЛЬНОГО ПРЕДСТАВЛЕНИЯ
# Параметры шаблона как для таблицы, плюс:
#   select_special  - названия всех служебных полей в виде списка:
#                       pkt_<field1> as ${SQL_FIELDPREFIX1}pkt_<field1>
#                       pkt_<field2> as ${SQL_FIELDPREFIX1}pkt_<field2>
#                       ...
#                       pkt_<fieldN> as ${SQL_FIELDPREFIX1}pkt_<fieldN>
#   changed_special - условие на изменение хотя бы одного из служебного
#                     поля (на основе шаблона SQL_DATA_PREPARE_VIEW_IF)
#   update_special  - обновление всех служебных полей (на основе шаблона
#                     SQL_DATA_PREPARE_VIEW_UPDATE)

SQL_DATA_PREPARE_VIEW=\
"
  ----------- Prepare data for view <table>

  CREATE TEMP TABLE <table>_${SQL_PREFIX_UNLOADTABLE}
  (
   <fields_def>
  );

  INSERT INTO <table>_${SQL_PREFIX_UNLOADTABLE}(<insert_fields>)
       SELECT <select_fields>
         FROM <owner>.<table>
        WHERE (
       <changed_special>
              )
   <filter> ;

  <update_special>

  INSERT INTO syncCOUNT SELECT count(*) FROM <table>_${SQL_PREFIX_UNLOADTABLE};

  COPY <table>_${SQL_PREFIX_UNLOADTABLE} TO '<file_data>' CSV;
"

# SQL-скрипт для формирования пакета - ДЛЯ ОТДЕЛЬНОГО ПРЕДСТАВЛЕНИЯ
# Условие на изменение отдельного служебного поля

SQL_DATA_PREPARE_VIEW_IF="<special_field> = 0 or \n <special_field> > (SELECT prepared FROM <schema>.syncNODES WHERE name = '<node>')"

# SQL-скрипт для формирования пакета - ДЛЯ ОТДЕЛЬНОГО ПРЕДСТАВЛЕНИЯ
# Для изменения отдельного служебного поля

SQL_DATA_PREPARE_VIEW_UPDATE="UPDATE <owner>.<table> \n SET <special_field> = (SELECT current_packet+1 FROM <schema>.syncMAIN)\n WHERE <special_field> = 0;"

# SQL-скрипт для формирования пакета - КОНЕЦ

SQL_DATA_PREPARE_AFTER=\
"
  -- Если были выгруженны хоть какие-либо данные...
  CREATE TEMP TABLE t_temp(packet integer);

  UPDATE <schema>.syncMAIN
     SET current_packet = current_packet + 1
   WHERE (SELECT sum(value) FROM syncCOUNT) > 0;

  INSERT INTO t_temp 
       SELECT case when (SELECT sum(value) FROM syncCOUNT) > 0
                      then current_packet
   else -1
      end
 FROM <schema>.syncMAIN;

  DELETE FROM t_temp WHERE (SELECT sum(packet) FROM t_temp) < 0;

  COPY t_temp TO '$SQL_COUNT_FILE';

"

# SQL-скрипт для обновления данных - НАЧАЛО

SQL_DATA_UPDATE_BEFORE=\
""

# SQL-скрипт для обновления данных - ДЛЯ ОТДЕЛЬНОЙ ТАБЛИЦЫ
# Параметры шаблона:
#   owner         - владелец таблицы
#   table         - имя таблицы
#   file_data     - полный путь и имя файла с данными таблицы с удаленной БД
#   file_del      - полный путь и имя файла со стертыми записями из таблицы
#                   с удаленной БД
#   fields_def    - определения всех полей таблицы (кроме служебных полей)
#                   из удаленной БД, перечисленные через запятую
#   select_fields - названия полей (кроме служебных), которые
#                   одновременно присутствуют в таблице в локальной и
#                   удаленной БД, в виде:
#                     $<field1> as $SQL_FIELDPREFIX1<field1>,
#                     $<field2> as $SQL_FIELDPREFIX1<field2>,
#                     ...
#                     $<fieldN> as $SQL_FIELDPREFIX1<fieldN>,
#   insert_fields - названия полей из common_fields в виде:
#                     $SQL_FIELDPREFIX2<field1>,
#                     $SQL_FIELDPREFIX2<field2>,
#                     ...
#                     $SQL_FIELDPREFIX2<fieldN>
#   insert_values - названия полей из insert_fields в виде:
#                     $SQL_FIELDPREFIX2<field1>,
#                     $SQL_FIELDPREFIX2<field2>,
#                     ...
#                     $SQL_FIELDPREFIX2<fieldN>
#   pkey_fields   - поля, входящие в первичный ключ таблицы в локальной
#                   БД в виде:
#                     <field1> = $SQL_FIELDPREFIX2<field1> and
#                     <field2> = $SQL_FIELDPREFIX2<field2> and
#                     ...
#                     <fieldN> = $SQL_FIELDPREFIX2<fieldN>
#   update_fields - поля из удаленной таблицы, значения по которым
#                   обновляются в локальной таблице (по другому -
#                   поля из common_fields за минусом pkey_fields)
#                   в виде:
#                     <field1> = $SQL_FIELDPREFIX2<field1>,
#                     <field2> = $SQL_FIELDPREFIX2<field2>,
#                     ...
#                     <fieldN> = $SQL_FIELDPREFIX2<fieldN>

# Примечания к реализации:
#
#  * В Sybase нет возможности обратиться напрямую к значениям
#    полей в курсоре. Реализуется это именованием полей
#    через 'as' в соответствующем select'е.
#  * Команда input не используется, так как она не может
#    выполняться в batch.
#  * Локальная временная таблица не используется, так как
#    команда load ее "не видит".
#  * Глобальная временная таблица объявляется как
#    on commit preserve rows, потому что так требует команда
#    load, которая по завершении делает commit.
#  * load предполагает расположение файлов на сервере.
#  * Sybase требует уникальности идентификатора курсора в пределах
#    скрипта. Поэтому в его имя добавлено имя таблицы.

SQL_DATA_UPDATE=\
"
  ----------- Update table <owner>.<table>

  CREATE TEMP TABLE <table>_${SQL_PREFIX_TEMPTABLE}
  (
   <fields_def>
  );

  COPY <table>_${SQL_PREFIX_TEMPTABLE} from '<file_del>' CSV QUOTE AS '''';


CREATE OR REPLACE FUNCTION <schema>.ftemp()
 RETURNS integer AS
\$BODY\$
DECLARE
  ${SQL_CURSORNAME} RECORD;
BEGIN

   FOR ${SQL_CURSORNAME} IN SELECT <select_fields> FROM <table>_${SQL_PREFIX_TEMPTABLE} LOOP

      DELETE FROM <owner>.<table> WHERE <pkey_fields>;

   END LOOP;
   
   return 1;
END;
\$BODY\$
LANGUAGE 'plpgsql'; 

SELECT <schema>.ftemp();

DROP FUNCTION <schema>.ftemp();


  TRUNCATE <table>_${SQL_PREFIX_TEMPTABLE};

  COPY <table>_${SQL_PREFIX_TEMPTABLE} from '<file_data>' CSV QUOTE AS '''';


CREATE OR REPLACE FUNCTION <schema>.ftemp()
 RETURNS integer AS
\$BODY\$
DECLARE
  ${SQL_CURSORNAME} RECORD;
BEGIN

   FOR ${SQL_CURSORNAME} IN SELECT <select_fields> FROM <table>_${SQL_PREFIX_TEMPTABLE} LOOP

      if exists(SELECT * FROM <owner>.<table> WHERE <pkey_fields>)
         then
            UPDATE <owner>.<table>
               SET
               <update_fields>
             WHERE
               <pkey_fields>;
         else
            INSERT INTO <owner>.<table>(<insert_fields>)
                 VALUES(<insert_values>);
      end if;

   END LOOP;
   
   return 1;
END;
\$BODY\$
LANGUAGE 'plpgsql'; 

SELECT <schema>.ftemp();

DROP FUNCTION <schema>.ftemp();


  DROP TABLE <table>_${SQL_PREFIX_TEMPTABLE};
"

# SQL-скрипт для обновления данных - КОНЕЦ

SQL_DATA_UPDATE_AFTER=\
"
  --------- End table section
$SQL_PACKET_UPDATED_SET
"

# Вернуть список всех полей определенной таблицы исключая системные поля.
# Список должен быть отсортирован по названию полей - сначала ключевые
# поля, затем все остальные.

SQL_FIELDLIST=\
"
SELECT t1.column_name
  FROM information_schema.columns AS t1
    LEFT JOIN information_schema.key_column_usage AS t2
           ON t1.table_schema = t2.table_schema
	  AND t1.table_name = t2.table_name
	  AND t1.column_name = t2.column_name
    LEFT JOIN information_schema.table_constraints AS t3
           ON t2.table_schema = t3.table_schema
	  AND t2.table_name = t3.table_name
	  AND t2.constraint_name = t3.constraint_name
 WHERE t1.table_schema = $SQL_UPPER('<owner>')
   AND t1.table_name = $SQL_UPPER('<table>')
   AND t1.column_name NOT IN ('$SQL_SYSFIELD1', '$SQL_SYSFIELD2')
   AND t1.column_name NOT LIKE 'pkt_%'
 GROUP BY t1.column_name
 ORDER BY sum(case when t3.constraint_type = 'PRIMARY KEY' then 1 else 0 end) desc, t1.column_name

"

# Вернуть список ключевых или неключевых полей определенной
# таблицы исключая системные поля.
# Список должен быть отсортирован по названию полей.

SQL_FIELDLIST_EX=\
"
SELECT t1.column_name
  FROM information_schema.columns AS t1
    LEFT JOIN information_schema.key_column_usage AS t2
           ON t1.table_schema = t2.table_schema
	  AND t1.table_name = t2.table_name
	  AND t1.column_name = t2.column_name
    LEFT JOIN information_schema.table_constraints AS t3
           ON t2.table_schema = t3.table_schema
	  AND t2.table_name = t3.table_name
	  AND t2.constraint_name = t3.constraint_name
 WHERE t1.table_schema = $SQL_UPPER('<owner>')
   AND t1.table_name = $SQL_UPPER('<table>')
   AND t1.column_name NOT IN ('$SQL_SYSFIELD1', '$SQL_SYSFIELD2')
   AND t1.column_name NOT LIKE 'pkt_%'
  GROUP BY t1.column_name 
  HAVING sum(case when t3.constraint_type = 'PRIMARY KEY' then 1 else 0 end) <equal_or_not> $SQL_FIELD_IN_PKEY
  ORDER BY t1.column_name

"

# Вернуть список всех служебных полей определенной таблицы

SQL_FIELDLIST_SPECIAL=\
"
SELECT t1.column_name
  FROM information_schema.columns AS t1
 WHERE t1.table_schema = $SQL_UPPER('<owner>')
   AND t1.table_name = $SQL_UPPER('<table>')
   AND t1.column_name LIKE 'pkt_%'
 ORDER BY t1.column_name

"

# Список метаданных о полях определенной таблицы исключая системные поля.
# Список должен состоять из строк с пятью полями, разделенных пробелом:
#   <имя поля> <входит в перв.ключ?> <код типа поля> <размер1> <размер2>
# и быть отсотрированным по названию полей - сначала ключевые поля,
# затем все остальные.

SQL_FIELDLIST_META=\
"
SELECT column_name || '$SQL_FIELD_SEPARATOR' || 
          sum(ord) || '$SQL_FIELD_SEPARATOR' || 
         data_type || '$SQL_FIELD_SEPARATOR' ||
    data_precision || '$SQL_FIELD_SEPARATOR' ||
     numeric_scale AS str
FROM (
  SELECT t1.column_name, 
         case when t3.constraint_type = 'PRIMARY KEY' then 1 else 0 end ord,
         lower(replace(replace(t1.data_type,' ','_'),'-','_')) data_type,
         case when t1.data_type like 'character%'
                 then coalesce(t1.character_maximum_length,1024)
              when t1.data_type = 'uuid'
                 then 36
              when t1.data_type = 'USER-DEFINED'
                 then 1024
              else COALESCE(t1.numeric_precision,t1.datetime_precision)
         end data_precision,
         COALESCE(t1.numeric_scale,0) numeric_scale
    FROM information_schema.columns AS t1
      LEFT JOIN information_schema.key_column_usage AS t2
             ON t1.table_schema = t2.table_schema
	    AND t1.table_name = t2.table_name
	    AND t1.column_name = t2.column_name
      LEFT JOIN information_schema.table_constraints AS t3
             ON t2.table_schema = t3.table_schema
	    AND t2.table_name = t3.table_name
	    AND t2.constraint_name = t3.constraint_name
   WHERE t1.table_schema = $SQL_UPPER('<owner>')
     AND t1.table_name = $SQL_UPPER('<table>')
     AND t1.column_name NOT IN ('$SQL_SYSFIELD1', '$SQL_SYSFIELD2')
) T
GROUP BY column_name, data_type, data_precision, numeric_scale
ORDER BY sum(ord) desc, column_name
"

# Вернуть что-либо, если указанная таблица является
# представлением (view)

SQL_ISVIEW=\
"
SELECT 1 FROM information_schema.tables
 WHERE table_schema = $SQL_UPPER('<owner>')
   AND table_name = $SQL_UPPER('<table>')
   AND table_type = 'VIEW'
"

# ********************************************************************
# sql_valuelist - Вернуть список значений из базы данных 
# -------------
# Параметры:
#   sqlname - имя переменной, хранящей SQL-выражение
#   sql     - необязательно. Само SQL-выражение,
#             возвращающее список значений
#
# Если не задан второй аргумент, то SQL-выражение берется из
# переменной, имя которой указанно в первом аргументе.
#
# В случае возникновения ошибки при выполнении SQL-выражения
# функция возвращает специальное значение $SQL_ERROR.
#
# Внимание! Реализация функции зависит от СУБД.

sql_valuelist()
{
  typeset sql tmpfile errfile list rawstr

  sqlname=$1
  sql="$2"

  tmpfile=$PATH_TEMP/$$-sql_valuelist.dat
  errfile=$PATH_TEMP/error_sql-$$.sql
  tmpfile1=$PATH_TEMP/$$-sql_valuelist1.dat

  if [ ! -x $SQL_EXEC ]
  then
    logmsg $ST_ERR 1 0 $0 "Программа \"$SQL_EXEC\" недоступна или не может быть выполнена"
    echo "$SQL_ERROR"
    return
  fi

  if [ -z "$sql" ]
  then
    sql="$(value_by_name $sqlname)"
    if [ -z "$sql" ]
    then
      logmsg $ST_ERR 1 0 $0 "Пустое SQL-выражение, которое дожно возвращать список значений"
      echo "$SQL_ERROR"
      return
    fi
  fi
  echo "$sql" > $tmpfile1

  # Получить список значений из БД

  $SQL_EXEC $tmpfile1 > $tmpfile 2> $errfile
  if [ $? -ne 0 ]
  then
    rm -f $tmpfile
    rm -f $tmpfile1
    echo "$sql" >> $errfile
    logmsg $ST_ERR 1 0 $0 "Ошибка при выполнении SQL-выражения \"$sqlname\". Выражение сохранено в файле \"$errfile\""
    echo "$SQL_ERROR"
    return
  fi
 
  list="`cat $tmpfile`"
  rm -f $tmpfile
  rm -f $tmpfile1
  rm -f $errfile

  rawstr=`printf "%s" "$list"`
  logmsg $ST_INFO 3 0 $0 "SQL-выражение \"$sqlname\" вернуло список \"$rawstr\""

  # Убрать кавычки вокруг значений, если они есть
  # (например, для строковых значений) и вернуть
  # итоговую строку

  replace "$list" "'" ""
}

# ********************************************************************
